<template>
  <div class="min-h-full pb-6 home">
    <div class="flex flex-col gap-8">
      <a-tabs type="card">
        <a-tab-pane key="1" tab="图片资源">
          <Typography>
            <Typography.Title :level="3">图片资源</Typography.Title>
            <img src="~@/assets/test.jpg" alt="" width="200" />
          </Typography>
        </a-tab-pane>
        <a-tab-pane key="2" tab="沙箱测试">
          <Typography>
            <Typography.Title :level="3">沙箱测试</Typography.Title>
            <div class="flex gap-4">
              <a-button @click="getBaseAppGlobalProperty">获取 window.testData</a-button>
              <a-button @click="setBaseAppGlobalProperty">修改 window.testData</a-button>
              <a-button @click="setGlobalProperty">子应用新增全局属性 count</a-button>
              <Typography.Link
                href="https://micro-zoe.github.io/micro-app/docs.html#/zh-cn/sandbox"
              >
                相关文档
              </Typography.Link>
              <Typography.Link href="https://github.com/micro-zoe/micro-app/issues/86">
                相关issues
              </Typography.Link>
            </div>
          </Typography>
        </a-tab-pane>
        <a-tab-pane key="3" tab="测试样式">
          <Typography>
            <Typography.Title :level="3">测试样式</Typography.Title>
            <Typography.Title :level="4">
              基本样式，给相同的div设置相同的class与样式，检测是否冲突
            </Typography.Title>
            <div class="style-box-1">背景色为红色</div>
            <Typography.Title :level="4">
              文字设置样式，子应用不设置，但使用相同的类型，颜色为红色（基座设置，当前颜色应该不变）
            </Typography.Title>
            <span class="style-text-1">我是一段文字</span>
            <blockquote>
              表现形式为红色，说明基座设置的样式对当前文字造成了响应，经过测试，当在基座应用中对相同的类名极元素等其他选择器设置样式时，子应用的样式会继承自全局的，所以基座中设置的样式对子应用是影响最大的，在子应用中设置的样式才属于完全被隔离的状态，因为它会在每个样式的前面选择选择器前缀，将子应用添加的样式限制在当前micro-app标签范围内，只能尽可能的避免使用标签选择器，以及在编写样式时启用vue的scoped功能及使用通过约定前缀或CSS
              Modules方式解决，不能解决的只能通过在子应用中进行样式覆盖。
            </blockquote>
            <Typography.Link href="https://micro-zoe.github.io/micro-app/docs.html#/zh-cn/scopecss">
              相关文档
            </Typography.Link>
            <Typography.Title :level="4"> 设置body与html的样式 </Typography.Title>
            <Typography.Text code>
              body { background-color: yellow; } html { color: pink; } .bbb { color: green; }
            </Typography.Text>
            <p class="!my-2">编译后的代码为</p>
            <Typography.Text class="Text" code>
              micro-app[name=xxx] { background-color: yellow; } micro-app[name=xxx] { color: pink; }
              micro-app[name=xxx] .bbb { color: green; }
            </Typography.Text>
            <blockquote>
              如上：在子应用中设置 html 和
              body的样式时，micro-app会将特定的几个选择器（html、body...）进行转换，变成
              micro-app[name=xxx]
            </blockquote>
            <p class="!my-2">通过查看源码我们发现：在加载子应用时顶层的选择器均会被替换掉。</p>
            <pre>
          // 处理顶层选择器，如 body，html 都转换为 micro-app[name=xxx]
          {
            if (/^((html[\s>~,]+body)|(html|body|:root))$/.test(selectorText)) {
              return cssText.replace(/^((html[\s>~,]+body)|(html|body|:root))/, prefix)
            } else if (selectorText === '*') {
              // 选择器 * 替换为 micro-app[name=xxx] *
              return cssText.replace('*', `${prefix} *`)
            }
          }
        </pre
            >
            micro-app 在0.8版本中 不在处理html的样式隔离，为原样返回。
          </Typography>
        </a-tab-pane>
        <a-tab-pane key="4" tab="元素隔离">
          <Typography>
            <Typography.Title :level="3">元素隔离</Typography.Title>
            <blockquote>
              引至官网：元素隔离的概念来自ShadowDom，即ShadowDom中的元素可以和外部的元素重复但不会冲突，micro-app模拟实现了类似ShadowDom的功能，元素不会逃离micro-app元素边界，子应用只能对自身的元素进行增、删、改、查的操作。
            </blockquote>
            <Typography.Title :level="4">ant-design UI测试</Typography.Title>
            <a-button @click="modalVisible = true">弹出modal</a-button>
            <a-modal
              v-model:visible="modalVisible"
              title="Basic Modal 子应用弹出"
              @ok="modalVisible = false"
            >
              <p>Some contents...</p>
              <p>Some contents...</p>
              <p>Some contents...</p>
            </a-modal>
            <blockquote>
              ant-design的modal等弹窗性组件，默认都是挂载到body上，此处测试子应用的在使用此等弹出组件时测试挂载位置的正确行，micro-app这个标签模拟了html标签，micro-app-body就相当于document.body，经测试发现ant-design的modal动态生产的dom挂载到了micro-app-body身上，且与基座表现无差异。
            </blockquote>
            <div class="flex gap-3">
              <a-button @click="getElementHeader">获取header</a-button>
              <a-button @click="getElementBody">获取body</a-button>
              <a-button @click="getRootEl">获取当前应用的根节点</a-button>
              <a-button @click="getClassTag">
                测试获取基座与子应用都存在相同节点的情况-class
              </a-button>
              <a-button @click="getIdTag">测试获取基座与子应用都存在相同节点的情况-id</a-button>
              <a-button @click="syncAppendToWrapper">测试动态插入一个子元素(body|子容器)</a-button>
            </div>
            <div class="test-class-tag-el">子应用节点 class</div>
            <div id="test-id-tag-el">子应用节点 id</div>
            <div class="sync-append-wrapper"> 测试动态插入一个子元素的容器： </div>
          </Typography>
        </a-tab-pane>
        <a-tab-pane key="5" tab="数据通信">
          <div class="flex gap-3">
            <a-button @click="getMicroAppData">window.microApp.getData() 获取数据</a-button>
          </div>
          <Typography>
            <blockquote>
              将基座下发的数据包装成响应式对象进行更改测试，数据变化时会进行严格对比(===)，相同的data对象不会触发更新
            </blockquote>
          </Typography>

          <div class="flex gap-3">
            <a-button @click="setMicroAppData">修改基座下发的count值</a-button>
            <a-button>{{ microData && microData.count }}</a-button>
          </div>
          <Typography>
            <blockquote>
              总结：基座传递给子应用的数据为一个对象格式，子应用获取的基座派发下来的数据是同一个引用地址，当子应用修改派发下来的数据时，基座的值也会变，而micro-app绑定的addDataListener监听函数对比数据是否发生变化而调用回调方法是使用了===进行数据判断，所以当修改对象中的某一个值得时候addDataListener是不会被触发的，只有派发下来的data的数据引用发生变化子应用的addDataListener监听函数才会被触发。
            </blockquote>
          </Typography>
          <div class="space-x-3">
            <a-button @click="dispatchData">子应用派发一条数据给基座</a-button>
          </div>
        </a-tab-pane>
      </a-tabs>
    </div>
  </div>
</template>

<script setup>
  import { Typography, message } from 'ant-design-vue';
  import { ref } from 'vue';

  function logInfo() {
    message.info('打开控制台查看输出结果');
  }

  function getBaseAppGlobalProperty() {
    message.info(`window.testData的值是 >>> ${String(window.testData)}`);
    console.log(window.testData);
    logInfo();
  }

  function setBaseAppGlobalProperty() {
    window.testData = 2;
    console.log(window.testData);
    logInfo();
  }

  function setGlobalProperty() {
    window.count = 10;
    message.success(
      '设置成功，点击主应用中对应的功能按钮，查看主应用是否可以获取到子应用设置的count值',
    );
    // 测试结果：子应用新增的全局属性不会泄漏给基座
  }

  /**
   * 总结：在基座应用中设置的全局window变量，在子应用中可以获取到，而子应用中新增与修改全局变量的作用域范围仅在子应用里生效，
   * 也就是说在子应用中新增与修改只在自己的作用于范围内，影响不到外界，但是可以获取到基座中挂载到window上的一些变量，
   *
   * 需要注意的是，子应用作用于内（沙箱环境中）通过var以及声明的function定义的顶层变量不会泄露成全局变量。
   *   例如：var count = 1;
   *        function getData() {};
   *  以上两个变量将不会映射到window上，即：window.count和window.getData的值都是undefined
   *  ps: 上面问题仅存在于沙箱环境下 # issues https://github.com/micro-zoe/micro-app/issues/86
   *
   *  # docs https://micro-zoe.github.io/micro-app/docs.html#/zh-cn/sandbox
   */

  const modalVisible = ref(false);

  function getElementHeader() {
    console.log(document.head); // 获取到的是基座的head
    logInfo();
  }

  function getElementBody() {
    console.log(document.body); // 获取到的是基座的body
    logInfo();
  }

  function getRootEl() {
    console.log(document.querySelector('#micro-app-vue3')); // 可以取到
    logInfo();
  }

  function getClassTag() {
    /**
     * 注意：子应用中创建的原始，在基座中都可以拿到，因为micro-app实现的元素隔离是模拟的ShadowDom（方便基座应用拥有绝对的控制权），而真正的ShadowDom是与外界严格隔离，内部访问不了外界，外界也访问不了内部（元素不会逃离<micro-app>元素边界，子应用只能对自身的元素进行增、删、改、查的操作。）docs:https://micro-zoe.github.io/micro-app/docs.html#/zh-cn/dom-scope
     *
     * 此处可以获取到 .test-class-tag-el 元素，而获取不到基座中创建的同类名元素，下面的id元素也是一个道理
     */
    console.log('single', document.querySelector('.test-class-tag-el'));
    console.log('all', document.querySelectorAll('.test-class-tag-el'));
    logInfo();
  }

  function getIdTag() {
    console.log('single', document.querySelector('#test-id-tag-el'));
    console.log('all', document.querySelectorAll('.test-id-tag-el'));
    logInfo();
  }

  function syncAppendToWrapper() {
    const a = document.createElement('a');
    a.href = '#';
    a.id = 'child-sync-append-wrapper';
    a.innerText = 'a链接元素';
    // 符合预期 创建出来的元素放入到了正确的地方
    document.querySelector('.sync-append-wrapper').appendChild(a);

    // 创建出来的元素并未插入到 html中的body下，而是插入到了micro-app中模拟的body micro-app-body标签下
    const a2 = document.createElement('a');
    a2.href = '#';
    a2.id = 'base-sync-append-wrapper';
    document.body.appendChild(a2);

    // quest: 设置其body的属性是可以的 如下
    // document.body.style.fontWeight = 'bold';
    // setTimeout(() => {
    //   document.body.innerHTML = '';
    // }, 3000);

    // 测试绑定事件 (是给顶层的body绑定的事件)
    // document.body.onclick = function () {
    //   console.log('click body');
    // };

    // 测试监听事件(是给顶层的body绑定的事件)
    // document.body.addEventListener('click', () => console.log('click body'));

    // 同上
    // window.document.body.addEventListener('click', () => console.log('click body'));
  }

  const microData = ref(null);

  function getMicroAppData() {
    console.log(window.microApp.getData());
  }

  function setMicroAppData() {
    microData.value && microData.value.count++;
  }

  // 监听基座下发的数据变化
  window.microApp.addDataListener(data => {
    console.log('micro-app-vue3 接收到的基座下发的数据变化值 >>> ', data);
    microData.value = data;
  }, true);

  function dispatchData() {
    window.microApp.dispatch({
      name: 'micro-app-vue3',
      data: {
        msg: '子应用的msg数据',
      },
    });
  }
</script>

<style lang="less" scoped>
  .style-box-1 {
    /* color: #fff; */
    background-color: red;
  }
  .aaa {
    font-size: 20;
  }
</style>

<style src="./index.less" lang="less"></style>
